package net.sf.midollo.commproxy;

import java.net.URL;
import java.util.Enumeration;

import javax.comm.CommPort;
import javax.comm.CommPortIdentifier;
import javax.comm.SerialPort;

import net.sf.midollo.io.DefaultIOStream;
import net.sf.midollo.io.IOStream;
import net.sf.midollo.net.io.SocketIOStreamFactory;
import net.sf.midollo.net.io.URLIOStreamFactory;
import net.sf.midollo.net.protocol.multitunnel.server.MultiTunnelServerFactory;
import net.sf.midollo.utils.Utils;

public class Main {

  protected String proxyName;
  protected String commPortName;
  protected boolean openAsFile = false;

  public static void main(String[] args) {
    try {
      new Main(args);
    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }

  public Main(String[] args) throws Exception {
    for (int i = 0; i < args.length; ++i) {
      if (args[i].equals("-l")) {
        listCommPorts();
        return;
      } else if (args[i].equals("-h")) {
        if (++i < args.length)
          proxyName = args[i];
      } else if (args[i].equals("-c")) {
        openAsFile = false;
        if (++i < args.length)
          commPortName = args[i];
      } else if (args[i].equals("-f")) {
        openAsFile = true;
        if (++i < args.length)
          commPortName = args[i];
      }
    }
    run();
  }

  protected String getPortTypeName(int portType) {
    switch (portType) {
      case CommPortIdentifier.PORT_PARALLEL:
        return "PARALLEL";
      case CommPortIdentifier.PORT_SERIAL:
        return "SERIAL";
    }
    return "?";
  }

  @SuppressWarnings("unchecked")
  protected void listCommPorts() {
    Enumeration commPortEnum = CommPortIdentifier.getPortIdentifiers();
    if (commPortEnum != null) {
      while (commPortEnum.hasMoreElements()) {
        CommPortIdentifier commPortIdentifier = (CommPortIdentifier)commPortEnum.nextElement();
        System.out.println(commPortIdentifier.getName() + " " + getPortTypeName(commPortIdentifier.getPortType()) + " " + commPortIdentifier.getCurrentOwner());
      }
    }
  }

  protected void run() throws Exception {
    Object[] hostAndPort = Utils.parseHostAndPort(this.proxyName);
    String proxyHost = Utils.getParsedHost(hostAndPort, "127.0.0.1");
    int proxyPort = Utils.getParsedPort(hostAndPort, 64080);
    SocketIOStreamFactory proxyFactory = new SocketIOStreamFactory(proxyHost, proxyPort);

    IOStream commIOStream;
    if (this.openAsFile) {
      // http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858%28v=vs.85%29.aspx

      // File commFile = new File(this.commPortName);
      // FileInputStream fis = new FileInputStream(commFile);
      // FileOutputStream fos = new FileOutputStream(commFile);
      // commIOStream = new DefaultIOStream(fis, fos);

      URL url = new URL(this.commPortName);
      URLIOStreamFactory urlFactory = new URLIOStreamFactory(url);
      commIOStream = urlFactory.open();

    } else {
      // Status for device COM3:
      // -----------------------
      // Baud: 115200
      // Parity: None
      // Data Bits: 8
      // Stop Bits: 1
      // Timeout: ON
      // XON/XOFF: OFF
      // CTS handshaking: ON
      // DSR handshaking: OFF
      // DSR sensitivity: OFF
      // DTR circuit: ON
      // RTS circuit: HANDSHAKE

      CommPortIdentifier portId = CommPortIdentifier.getPortIdentifier(this.commPortName);
      CommPort commPort = portId.open(Main.class.getName(), 0);
      // commPort.enableReceiveThreshold(32);
      // commPort.enableReceiveTimeout(250);
      System.out.println("timeout " + commPort.isReceiveTimeoutEnabled() + " " + commPort.getReceiveTimeout());
      System.out.println("threshold " + commPort.isReceiveThresholdEnabled() + " " + commPort.getReceiveThreshold());
      System.out.println("inbuf " + commPort.getInputBufferSize());
      System.out.println("outbuf " + commPort.getOutputBufferSize());
      if (commPort instanceof SerialPort) {
        SerialPort serialPort = (SerialPort)commPort;
        // serialPort.setRTS(true);
        // serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_RTSCTS_IN | SerialPort.FLOWCONTROL_RTSCTS_OUT);
        serialPort.setSerialPortParams(115200, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
        System.out.println("baud " + serialPort.getBaudRate());
        System.out.println("parity " + serialPort.getParity());
        System.out.println("data bits " + serialPort.getDataBits());
        System.out.println("stop " + serialPort.getStopBits());
        System.out.println("flow " + serialPort.getFlowControlMode());
        System.out.println("cts " + serialPort.isCTS());
        System.out.println("rts " + serialPort.isRTS());
      }
      commIOStream = new DefaultIOStream(commPort.getInputStream(), commPort.getOutputStream());
    }

    MultiTunnelServerFactory tunnelServer = new MultiTunnelServerFactory(proxyFactory, 32);
    Utils.log("run tunnel server");
    tunnelServer.runTunnelServer(commIOStream);
  }
}
